package unit;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.text.ParseException;
import java.util.ArrayList;

import junit.framework.TestCase;

import com.google.code.netcheckin.aprs.Station;
import com.google.code.netcheckin.io.StationDbReader;

public class UStationDbReader extends TestCase {

	public static final String CSV_INPUT = 
	  "PrimaryIcon,PrimaryAddress,CallSign\n"
	+ "/-,2122 Antennaless Ln,KC9JLU\n"
	+ "/[,1706 Antenna Ln,KB9JHU\n"
	+ "/[,\"6 Antenna, Ln\",N9FEB\n"
	;

	public static final String CSV_MISSING_INPUT =
	  "CallSign,PrimaryLatDegrees,PrimaryLatMinutes,PrimaryLatDirection"
	+ ",PrimaryLongDegrees,PrimaryLongMinutes,PrimaryLongDirection"
	+ ",SecondaryLatDegrees,SecondaryLatMinutes,SecondaryLatDirection"
	+ ",SecondaryLongDegrees,SecondaryLongMinutes,SecondaryLongDirection\n"
	+ "1,,17.21,N,86,18.1,W,40,17.6,S,122,17.7,E\n" 
	+ "2,39,,N,86,18.1,W,40,17.6,S,122,17.7,E\n" 
	+ "3,39,21.2,N,,18.1,W,40,17.6,S,122,17.7,E\n" 
	+ "4,39,21.2,N,86,,W,40,17.6,S,122,17.7,E\n" 
	+ "5,39,21.2,,86,31.8,E,40,17.6,S,122,17.7,E\n" 
	+ "6,39,21.2,S,86,31.8,,40,17.6,S,122,17.7,E\n" 
	+ "7,39,21.2,S,86,31.8,E,,17.6,S,122,17.7,E\n" 
	+ "8,39,21.2,S,86,31.8,E,41,,S,122,17.7,E\n" 
	+ "9,39,21.2,S,86,31.8,E,41,45.9,,122,17.7,E\n" 
	+ "10,39,21.2,S,86,31.8,E,41,45.9,S,,17.7,E\n" 
	+ "11,39,21.2,S,86,31.8,E,41,45.9,S,123,,E\n" 
	+ "12,39,21.2,S,86,31.8,E,41,45.9,S,123,14,\n" 
	;

	//+ ",SecondaryLatDegrees,SecondaryLatMinutes,SecondaryLatDirection\n"

	public UStationDbReader(String name) {
		super(name);
	}

	public void testAAFindColumnNameIdx() {
		TestStationDbReader tsdr = new TestStationDbReader(
						new StringReader("x"));
				// first in list
		int answer = tsdr.testFindColumnNameIdx(
		     StationDbReader.COL_NAMES[StationDbReader.IDX_CALL_SGN]);	
		assertEquals("1 wrong", StationDbReader.IDX_CALL_SGN, answer);
				// end of list
		answer = tsdr.testFindColumnNameIdx(
		     StationDbReader.COL_NAMES[StationDbReader.IDX_SEC_ICON]);	
		assertEquals("2 wrong", StationDbReader.IDX_SEC_ICON, answer);
				// somewhere in middle
		answer = tsdr.testFindColumnNameIdx(
		     StationDbReader.COL_NAMES[StationDbReader.IDX_RACES]);	
		assertEquals("3 wrong", StationDbReader.IDX_RACES, answer);
				// does not exit
		answer = tsdr.testFindColumnNameIdx("XXXXXXXXXXXX");	
		assertEquals("4 wrong", -1, answer);
	}

	public void testABGetColumnIds() {
		// do this by placing names in reverse order
		TestStationDbReader tsdr = new TestStationDbReader(new StringReader("x"));
		int start = StationDbReader.COL_NAMES.length - 1;
		ArrayList names = new ArrayList();
		for (int idx = start; idx >= 0; idx --) {
			names.add(StationDbReader.COL_NAMES[idx]);
		}
		int[] colids = tsdr.testGetColumnIds(names);
		// test the result
		int ceil = colids.length;
		for (int idx = 0; idx < ceil; idx ++) {
			int answer = ceil - idx - 1;
			assertEquals("wrong colid", answer, colids[idx]);
		}
	}

	public void testABHGetInputColumnName() {
		TestStationDbReader tsdr = new TestStationDbReader(new StringReader("x"));
		ArrayList names = new ArrayList();
		names.add(StationDbReader.COL_NAMES[
				StationDbReader.IDX_PRIM_LAT_DEG]);
		names.add(StationDbReader.COL_NAMES[
				StationDbReader.IDX_CALL_SGN]);
		tsdr.testGetColumnIds(names);
		assertEquals("col 0 bad", (String)names.get(0),
				tsdr.testGetInputColumnName(0));
		assertEquals("col 1 bad", (String)names.get(1),
				tsdr.testGetInputColumnName(1));
	}

	public void testACParseCoordinateMinutes() {
		TestStationDbReader tsdr = new TestStationDbReader(new StringReader("x"));
	   try {
		float answer = tsdr.testParseCoordinateMinutes("12.75");
		assertEquals("12.75 failed", new Float(12.75).floatValue(),
				answer);
	   } catch(Exception e) {
		System.out.print(e.getMessage());
		e.printStackTrace();
		fail(e.getMessage());
	   }
	   try {
		float answer = tsdr.testParseCoordinateMinutes("1x.75");
		fail("1x.75 no exception");
	   } catch(Exception e) {
		assertNotNull("OK", e);
	   }
	   try {
		float answer = tsdr.testParseCoordinateMinutes("175.75");
		fail("175.75 no exception");
	   } catch(Exception e) {
		assertNotNull("OK", e);
	   }
	}

	public void testADParseLatitudeDegrees() {
		TestStationDbReader tsdr = new TestStationDbReader(new StringReader("x"));
	   try {
		int answer = tsdr.testParseLatitudeDegrees("65");
		assertEquals("65 failed", 65, answer);
	   } catch(Exception e) {
		System.out.print(e.getMessage());
		e.printStackTrace();
		fail(e.getMessage());
	   }
	   try {
		int answer = tsdr.testParseLatitudeDegrees("6x");
		fail("xx no exception");
	   } catch(Exception e) {
		assertNotNull("OK", e);
	   }
	   try {
		int answer = tsdr.testParseLatitudeDegrees("91");
		fail("91 no exception");
	   } catch(Exception e) {
		assertNotNull("OK", e);
	   }
	}

	public void testAEParseLongitudeDegrees() {
		TestStationDbReader tsdr = new TestStationDbReader(new StringReader("x"));
	   try {
		int answer = tsdr.testParseLongitudeDegrees("91");
		assertEquals("91 failed", 91, answer);
	   } catch(Exception e) {
		System.out.print(e.getMessage());
		e.printStackTrace();
		fail(e.getMessage());
	   }
	   try {
		int answer = tsdr.testParseLongitudeDegrees("6x");
		fail("xx no exception");
	   } catch(Exception e) {
		assertNotNull("OK", e);
	   }
	   try {
		int answer = tsdr.testParseLongitudeDegrees("181");
		fail("181 no exception");
	   } catch(Exception e) {
		assertNotNull("OK", e);
	   }
	}

	//
	// The following long list of tests is intended to
	// ensure that data are put in the correct fields
	// within a station object. One test method is used
	// per field for "parallel" testing. For fields for which
	// values are checked, a test is also made using a bad value.
	// The result of that test should be that createStation returns
	// null.
	//

	public void testAFStationCallSign() {
		System.err.println("Lines beginning Error: bad value in"
			+ " line 1 are OK - desired results for some tests");
		Station stn = createStation(StationDbReader.IDX_CALL_SGN);
		assertEquals("call failed", "HELLO", stn.getCallsign());
	}

	public void testAGStationName() {
		Station stn = createStation(StationDbReader.IDX_NAME);
		assertEquals("call failed", "HELLO", stn.getName());
	}

	public void testAHAres() {
		Station stn = createStation(StationDbReader.IDX_ARES, "yes");
		assertTrue("1 failed", stn.getIsAres());
		stn = createStation(StationDbReader.IDX_ARES, "no");
		assertFalse("2 failed", stn.getIsAres());
	}

	public void testAIRaces() {
		Station stn = createStation(StationDbReader.IDX_RACES, "yes");
		assertTrue("1 failed", stn.getIsRaces());
		stn = createStation(StationDbReader.IDX_RACES, "no");
		assertFalse("2 failed", stn.getIsRaces());
	}

	public void testAJCellPhone() {
		Station stn = createStation(StationDbReader.IDX_CELLPHONE);
		assertEquals("call failed", "HELLO", stn.getCellphone());
	}

	public void testAKEmail() {
		Station stn = createStation(StationDbReader.IDX_EMAIL);
		assertEquals("call failed", "HELLO", stn.getEmail());
	}

	public void testAKFPrimaryDescription() {
		Station stn = createStation(StationDbReader.IDX_PRIM_DESCR);
		assertEquals("call failed", "HELLO", stn.getPrimaryDescription());
        }

	public void testALPrimAddr() {
		Station stn = createStation(StationDbReader.IDX_PRIM_ADDR);
		assertEquals("call failed", "HELLO", stn.getPrimaryAddress());
	}
 
	public void testAMPrimCity() {
		Station stn = createStation(StationDbReader.IDX_PRIM_CITY);
		assertEquals("call failed", "HELLO", stn.getPrimaryCity());
	}
 
	public void testANPrimState() {
		Station stn = createStation(StationDbReader.IDX_PRIM_STATE);
		assertEquals("call failed", "HELLO", stn.getPrimaryState());
	}
 
	public void testAOPrimZip() {
		Station stn = createStation(StationDbReader.IDX_PRIM_ZIP);
		assertEquals("call failed", "HELLO", stn.getPrimaryZip());
	}

	public void testAQPrimLatDegrees() {
		Station stn = createStation(StationDbReader.IDX_PRIM_LAT_DEG,
					"85");
		assertEquals("call failed", 85, stn.getPrimaryLatitude1());
			// check bogus value
		stn = createStation(StationDbReader.IDX_PRIM_LAT_DEG, "x5");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_PRIM_LAT_DEG, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testARPrimLatMinutes() {
		Station stn = createStation(StationDbReader.IDX_PRIM_LAT_MIN,
					"31.2");
		assertEquals("call failed", new Float(31.2).floatValue(), 
					stn.getPrimaryLatitude2());
		stn = createStation(StationDbReader.IDX_PRIM_LAT_MIN,
					"3x.2");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_PRIM_LAT_MIN, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testASPrimLatDir() {
		Station stn = createStation(StationDbReader.IDX_PRIM_LAT_DIR,
					"N");
		assertEquals("call failed", 'N', 
					stn.getPrimaryLatitudeOrientation());
		stn = createStation(StationDbReader.IDX_PRIM_LAT_DIR, "E");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_PRIM_LAT_DIR, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testATPrimLongDegrees() {
		Station stn = createStation(StationDbReader.IDX_PRIM_LONG_DEG,
					"175");
		assertEquals("call failed", 175, stn.getPrimaryLongitude1());
		stn = createStation(StationDbReader.IDX_PRIM_LONG_DEG, "x");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_PRIM_LONG_DEG, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testAUPrimLongMinutes() {
		Station stn = createStation(StationDbReader.IDX_PRIM_LONG_MIN,
					"31.2");
		assertEquals("call failed", new Float(31.2).floatValue(), 
					stn.getPrimaryLongitude2());
		stn = createStation(StationDbReader.IDX_PRIM_LONG_MIN, "3j.2");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_PRIM_LONG_MIN, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testAVPrimLongDir() {
		Station stn = createStation(StationDbReader.IDX_PRIM_LONG_DIR,
					"E");
		assertEquals("call failed", 'E', 
					stn.getPrimaryLongitudeOrientation());
		stn = createStation(StationDbReader.IDX_PRIM_LONG_DIR, "F");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_PRIM_LONG_DIR, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testAWPrimIcon() {
	  try {
		Station stn = createStation(StationDbReader.IDX_PRIM_ICON,
					"/-");
		assertEquals("call failed", "/-", stn.getPrimaryIcon());
		stn = createStation(StationDbReader.IDX_PRIM_ICON, "XX");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_PRIM_ICON, "");
		assertNotNull("missing caused null", stn);
	  } catch(Exception e) {
		System.out.println(e.getMessage());
		e.printStackTrace();
		fail(e.getMessage());
	  }
	}

	public void testAWQSecondaryDescription() {
		Station stn = createStation(StationDbReader.IDX_SEC_DESCR);
		assertEquals("call failed", "HELLO", stn.getSecondaryDescription());
        }


	public void testAXSecAddr() {
		Station stn = createStation(StationDbReader.IDX_SEC_ADDR);
		assertEquals("call failed", "HELLO", stn.getSecondaryAddress());
	}
 
	public void testAYSecCity() {
		Station stn = createStation(StationDbReader.IDX_SEC_CITY);
		assertEquals("call failed", "HELLO", stn.getSecondaryCity());
	}
 
	public void testAZSecState() {
		Station stn = createStation(StationDbReader.IDX_SEC_STATE);
		assertEquals("call failed", "HELLO", stn.getSecondaryState());
	}
 
	public void testBASecZip() {
		Station stn = createStation(StationDbReader.IDX_SEC_ZIP);
		assertEquals("call failed", "HELLO", stn.getSecondaryZip());
	}
 
	public void testBBSecLatDegrees() {
		Station stn = createStation(StationDbReader.IDX_SEC_LAT_DEG,
					"85");
		assertEquals("call failed", 85, stn.getSecondaryLatitude1());
		stn = createStation(StationDbReader.IDX_SEC_LAT_DEG, "185");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_SEC_LAT_DEG, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testBCSecLatMinutes() {
		Station stn = createStation(StationDbReader.IDX_SEC_LAT_MIN,
					"31.2");
		assertEquals("call failed", new Float(31.2).floatValue(), 
					stn.getSecondaryLatitude2());
		stn = createStation(StationDbReader.IDX_SEC_LAT_MIN, "81.2");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_SEC_LAT_MIN, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testBDSecLatDir() {
		Station stn = createStation(StationDbReader.IDX_SEC_LAT_DIR,
					"N");
		assertEquals("call failed", 'N', 
					stn.getSecondaryLatitudeOrientation());
		stn = createStation(StationDbReader.IDX_SEC_LAT_DIR, "J");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_SEC_LAT_DIR, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testBESecLongDegrees() {
		Station stn = createStation(StationDbReader.IDX_SEC_LONG_DEG,
					"175");
		assertEquals("call failed", 175, stn.getSecondaryLongitude1());
		stn = createStation(StationDbReader.IDX_SEC_LONG_DEG, "195");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_SEC_LONG_DEG, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testBFSecLongMinutes() {
		Station stn = createStation(StationDbReader.IDX_SEC_LONG_MIN, 
						"31.2");
		assertEquals("call failed", new Float(31.2).floatValue(), 
					stn.getSecondaryLongitude2());
		stn = createStation(StationDbReader.IDX_SEC_LONG_MIN, "31,2");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_SEC_LONG_MIN, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testBGSecLongDir() {
		Station stn = createStation(StationDbReader.IDX_SEC_LONG_DIR,
					"E");
		assertEquals("call failed", 'E', 
					stn.getSecondaryLongitudeOrientation());
		stn = createStation(StationDbReader.IDX_SEC_LONG_DIR, "N");
		assertNull("not null", stn);
		stn = createStation(StationDbReader.IDX_SEC_LONG_DIR, "");
		assertNotNull("missing caused null", stn);
	}
 
	public void testBHSecIcon() {
	  try {
		Station stn = createStation(StationDbReader.IDX_SEC_ICON,
					"/-");
		assertEquals("call failed", "/-", stn.getSecondaryIcon());
		stn = createStation(StationDbReader.IDX_SEC_ICON, "/~");
		assertNull("not null", stn);
		System.err.println("NO Error: bad value in line 1 messages"
			+ " should follow this line");
		stn = createStation(StationDbReader.IDX_SEC_ICON, "");
		assertNotNull("missing caused null", stn);
	  } catch(Exception e) {
		System.out.println(e.getMessage());
		e.printStackTrace();
		fail(e.getMessage());
	  }
	}
 
	public void testBHTComment() {
		Station stn = createStation(StationDbReader.IDX_COMMENT);
		assertEquals("call failed", "HELLO", stn.getComment());
	}

	//
	// Test the read method using a small data set
	//

	public void testBIRead() {
	   try {
		StationDbReader reader = new StationDbReader(new StringReader(CSV_INPUT));
		Object[] answer = reader.read();
		assertNotNull("answer null", answer);
		assertEquals("wrong size", 3, answer.length);
		Station astn = (Station)answer[0];
		assertEquals("KB9JHU not first", "KB9JHU", astn.getCallsign());
		astn = (Station)answer[1];
		assertEquals("KC9JLU not second", "KC9JLU", astn.getCallsign());
		astn = (Station)answer[2];
		assertEquals("N9FEB bad quotes", "6 Antenna, Ln", 
				astn.getPrimaryAddress());
		reader.close();
	   } catch(IOException ioe) {
		System.out.println(ioe.getMessage());
		ioe.printStackTrace();
		fail(ioe.getMessage());
	   }
	}

	public void testBJMissingNumerics() {
	  try {
		StationDbReader reader = new StationDbReader(new StringReader(
			CSV_MISSING_INPUT));
		Object[] answer = reader.read();
		assertNotNull("answer null", answer);
		assertEquals("wrong size", 12, answer.length);
		Station astn = (Station)answer[0];
	   } catch(IOException ioe) {
		System.out.println(ioe.getMessage());
		ioe.printStackTrace();
		fail(ioe.getMessage());
	   }
	}

	///////////////////// protected below ///////////////////////////////

	protected Station createStation(int idx) {
		return createStation(idx, "HELLO");
	}

	protected Station createStation(int idx, String value) {
		TestStationDbReader tsdr = new TestStationDbReader(
					new StringReader("x"));
		ArrayList al = new ArrayList(1);
		al.add(StationDbReader.COL_NAMES[idx]);
		tsdr.testGetColumnIds(al);
		int colnidx = tsdr.testFindColumnNameIdx(
		   StationDbReader.COL_NAMES[idx]);
		ArrayList data = new ArrayList(1);
		data.add(value);
		return tsdr.testCreateStation(data, 1);
	}


	/////////////////////////////////////////////////////////////////////

		/** Expose protected methods and fields. */

	public static class TestStationDbReader extends StationDbReader {
		public TestStationDbReader(Reader r) {
			super(r);
		}

		public int testFindColumnNameIdx(final String name) {
			return findColumnNameIdx(name);
		}

		public int[] testGetColumnIds(ArrayList names) {
			getColumnIds(names);
			return colId;
		}

		public String testGetInputColumnName(int icolidx) {
			return getInputColumnName(icolidx);
		}

		public Station testCreateStation(ArrayList data, int rowidx) {
			return createStation(data, rowidx);
		}

		public float testParseCoordinateMinutes(String str) 
						throws ParseException {
			return parseCoordinateMinutes(str);
		}

		public int testParseLatitudeDegrees(String str) 
						throws ParseException {
			return parseLatitudeDegrees(str);
		}

		public int testParseLongitudeDegrees(String str) 
						throws ParseException {
			return parseLongitudeDegrees(str);
		}
	}
}
